#include "media_session.h"
#include "rtsp_context.h"

using namespace VLRTSP;


/**
 * @Author: CimZzz
 * @Date: 2022-01-13 15:38:48
 * 
 * 构造函数
 * @param sessionId 会话 Id
 */
MediaSession::MediaSession(const char * sessionId): sessionId(sessionId) {
	this->isAttached = false;
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-07 11:47:52
 * 
 * 添加新的媒体资源
 * 
 * @param source 媒体资源
 * 
 * @note 注意，一旦将媒体资源安装到 RTSP 服务器后，不再允许添加媒体资源
 */
void MediaSession::addMediaSource(MediaSource* source) {
	if(this->isAttached) {
		delete source;
		return;
	}
	uint32_t sourceId = code.getCode();
	code.nextCode();
	sourceList.push_back(std::shared_ptr<MediaSource>(source));
	source->_attachSession(this, sourceId);
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-12 23:06:21
 * 
 * 返回媒体会话 Id
 * @return 媒体会话 Id
 */
std::string MediaSession::getSessionId() {
	return this->sessionId;
}


/**
 * @Author: CimZzz
 * @Date: 2022-01-13 16:37:20
 * 
 * 获取 SDP 描述文件
 * @param ip 访问 IP 地址
 * @param buffer 字节缓冲区
 */
void MediaSession::buildSDP(std::string ip, Buffer* buffer) {
	if(this->sourceList.empty()) {
		return;
	}

	// 关于会话信息
	buffer->appendPrint(
		"v=0\r\n"
		"o=- 9%ld 1 IN IP4 %s\r\n"
		"t=0 0\r\n"
		"a=control:*\r\n"
		"s=%s\r\n",
		(long)std::time(NULL),
		ip.c_str(),
		sessionId.c_str()
	);

	// todo 多播支持

	// 关于媒体资源信息
	for(auto iter = this->sourceList.begin() ; iter != this->sourceList.end() ; iter ++) {
		MediaSource* source = iter->get();
		source->buildSourceSDP(buffer);
		buffer->appendPrint(
			"a=control:track%d\r\n",
			source->getSouceId()
		);
	}
}


/**
 * @Author: CimZzz
 * @Date: 2022-01-14 11:05:32
 * 
 * 根据媒体资源 Id 找到媒体资源
 * @param sourceId 媒体资源 Id
 * @return 找到的媒体资源，如果没找到指针为 nullptr
 */
std::shared_ptr<MediaSource> MediaSession::findMediaSource(uint32_t sourceId) {
	if(sourceId >= this->sourceList.size()) {
		return std::shared_ptr<MediaSource>(nullptr);
	}

	return this->sourceList.at(sourceId);
}

/**
 * @Author: CimZzz
 * @Date: 2022-01-07 11:57:38
 * 
 * 贴附上 RTSP 服务器
 * @param context RTSP 上下文
 */
void MediaSession::_attachRTSPServer(RTSPContext* context) {
	this->isAttached = true;
	this->context = context;
}